package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.Constants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ResourceServiceImpl implements ResourceService {

    private final ResourceMapper resourceMapper;

    /**
     * 查询资源列表
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheConstant.RESOURCE_LIST, key = "#resourceDto.hashCode()")
    public List<ResourceVo> resourceList(ResourceDto resourceDto) {
        List<Resource> resourceList = resourceMapper.selectResourceList(resourceDto);
        return BeanUtil.copyToList(resourceList, ResourceVo.class);
    }

    /**
     * 查询资源树
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheConstant.RESOURCE_TREE )
    public TreeVo resourceTree(ResourceDto resourceDto) {
        //构建查询条件
        ResourceDto dto = ResourceDto.builder().dataState(SuperConstant.DATA_STATE_0)
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))
                .resourceType(SuperConstant.MENU)
                .build();
        //查询所有资源数据
        List<Resource> resourceList = resourceMapper.selectResourceList(dto);
        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            throw new BaseException(BasicEnum.RESOURCE_NOT_EXIST);
        }
        //没有根节点，构建根节点
        Resource rootResource = new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        rootResource.setResourceName(Constants.Super_Label);

        //构建树形集合
        List<TreeItemVo> itemVos = new ArrayList<>();

        //使用递归构建树形结构
        recursionTreeItem(itemVos, rootResource, resourceList);

        //数据返回
        return TreeVo.builder().items(itemVos).build();
    }

    /**
     * 新增资源
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public void addResource(ResourceDto resourceDto) {
        boolean isIgnore = true;
        //判断是按钮还是菜单,是按钮不限制层级
        if (SuperConstant.BUTTON.equals(resourceDto.getResourceType())){
            isIgnore = false;
        }
        //创建资源编号
        String resourceNo = createResourceNo(resourceDto.getParentResourceNo(),isIgnore);
        //属性拷贝
        Resource resource = BeanUtil.copyProperties(resourceDto, Resource.class);
        //查询父资源状态,新增资源状态与父资源状态保持一致
        Resource parent = resourceMapper.selectDataStateByResourceNo(resourceDto.getParentResourceNo());
        if (null != parent) {
            resource.setDataState(parent.getDataState());
        }
        //插入
        resource.setResourceNo(resourceNo);
        resourceMapper.insert(resource);
    }

    /**
     * 修改资源
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public void updateResource(ResourceDto resourceDto) {
        //属性拷贝
        Resource resource = BeanUtil.copyProperties(resourceDto, Resource.class);
        //没有子资源则更新该资源
        resourceMapper.updateByPrimaryKeySelective(resource);

    }

    /**
     * 资源启用禁用
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public Boolean updateStatus(ResourceDto resourceDto) {
        //启用菜单
        if (SuperConstant.DATA_STATE_0.equals(resourceDto.getDataState())) {
            //判断父级菜单是否是禁用，如果是禁用，不允许启用
            String parentResourceNo = resourceDto.getParentResourceNo();
            Resource parentResource = resourceMapper.selectDataStateByResourceNo(parentResourceNo);
            if (SuperConstant.DATA_STATE_1.equals(parentResource.getDataState())) {
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }

        //判断按钮是否被分配
        if (resourceDto.getResourceType().equals("r")){
            List<Resource> resourceList = resourceMapper.selectResourceByResourceType(resourceDto.getResourceType());
            if (!EmptyUtil.isNullOrEmpty(resourceList)){
                throw new BaseException(BasicEnum.BUTTON_DISTRIBUTED);
            }
        }
        //判断是否有子菜单，如果有子菜单，则一起启用或禁用
        String resourceNo = resourceDto.getResourceNo();
        resourceMapper.updateByResourceNo(resourceNo, resourceDto.getDataState());
        Integer count = resourceMapper.updateByParentResourceNo(NoProcessing.processString(resourceNo), resourceDto.getDataState());
        return count > 0;
    }

    /**
     * 删除菜单
     * @param menuId
     */
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(cacheNames = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public void delete(Long menuId) {
        if (hasChildResource(menuId.toString())){
            throw new BaseException(BasicEnum.CHILD_RESOURCE_NOT_DELETED);
        }
        Resource resource = resourceMapper.selectDataStateByResourceNo(menuId.toString());
        if (resource != null && SuperConstant.DATA_STATE_0.equals(resource.getDataState())){
            throw new BaseException(BasicEnum.ENABLED_CANNOT_DELETED);
        }
        resourceMapper.deleteByResourceNo(menuId.toString());
    }

    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if (CollUtil.isEmpty(menuVoList)) {
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组（parentNo:[{},{}]）
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        menuVoList.forEach(menuVo -> {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/"+menuVo.getName());
            //根据父编号到map中查找是否包含子菜单，如果包含则设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(menuVos)){
                menuVos.forEach(m->{
                    m.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
                    m.setRedirect(m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        });
        //根据根编号查找所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }


    /**
     * 判断是否有子资源
     * @param resourceNo
     * @return
     */
    private Boolean hasChildResource(String resourceNo) {
        Integer count = resourceMapper.selectResourceByResourceNo(resourceNo);
        return count > 0;
    }


    /**
     * 创建资源编号
     * @param parentResourceNo
     * @param isIgnore
     * @return
     */
    private String createResourceNo(String parentResourceNo, boolean isIgnore) {
        //判断层级是否大于3
        if (isIgnore && NoProcessing.processString(parentResourceNo).length() / 3 >= 5){
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //查询父资源下是否有子资源
        ResourceDto resourceDto = new ResourceDto();
        resourceDto.setParentResourceNo(parentResourceNo);
        List<Resource> childList = resourceMapper.selectResourceList(resourceDto);
        //如果没有
        if (CollectionUtil.isEmpty(childList)){
            //根据父资源编号创建新的编号
            return NoProcessing.createNo(parentResourceNo,false);
        }else {
            //有则根据已有子资源追加
            //拿到最大的编号
            String maxNo = childList.stream().map(Resource::getResourceNo).max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(maxNo,true);
        }
    }

    /**
     * 使用递归构建树形结构
     * @param itemVos
     * @param rootResource
     * @param resourceList
     */
    private void recursionTreeItem(List<TreeItemVo> itemVos, Resource rootResource, List<Resource> resourceList) {
        //构建每个资源的属性
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(rootResource.getResourceNo())
                .label(rootResource.getResourceName()).build();

        //获取当前资源下子资源
        List<Resource> childrenResourceList = resourceList.stream()
                .filter(n -> n.getParentResourceNo().equals(rootResource.getResourceNo()))
                .collect(Collectors.toList());
        //判断子资源是否为空
        if (!EmptyUtil.isNullOrEmpty(childrenResourceList)) {

            List<TreeItemVo> listChildren = new ArrayList<>();
            //构建子资源
            childrenResourceList.forEach(resource -> {
                recursionTreeItem(listChildren, resource, resourceList);
            });
            treeItemVo.setChildren(listChildren);
        }
        itemVos.add(treeItemVo);
    }
}
